using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using Renderer.Utils;

namespace Renderer.DataStructures
{
    [Serializable]
    struct Vector3D
    {
        double x, y, z;

        public double X
        {
            get { return x; }
            set { x = value; }
        }

        public double Y
        {
            get { return y; }
            set { y = value; }
        }

        public double Z
        {
            get { return z; }
            set { z = value; }
        }

        public Vector3D(double x, double y, double z)
        {
            this.x = x;
            this.y = y;
            this.z = z;
        }

        /// <summary>
        /// Scalar(dot) product
        /// </summary>
        /// <param name="v1"></param>
        /// <param name="v2"></param>
        /// <returns></returns>
        public static double operator *(Vector3D v1, Vector3D v2)
        {
            return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
        }

        public static Vector3D operator *(Vector3D v, double s)
        {
            return s * v;
        }

        public static Vector3D operator *(double s, Vector3D v)
        {
            return new Vector3D(s * v.x, s * v.y, s * v.z);
        }

        public Vector3D Mul(double s)
        {
            x *= s;
            y *= s;
            z *= s;
            return this;
        }
        
        /// <summary>
        /// Vector product
        /// </summary>
        /// <param name="v1"></param>
        /// <param name="v2"></param>
        /// <returns></returns>
        public static Vector3D operator ^(Vector3D v1, Vector3D v2)
        {
            return new Vector3D(v1.y * v2.z - v2.y * v1.z, v1.z * v2.x - v2.z * v1.x, v1.x * v2.y - v2.x * v1.y);
        }         
        
        
        /// <summary>
        /// Vector product
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        public Vector3D Cross(Vector3D v)
        {
            x = y * v.z - v.y * z;
            y = z * v.x - v.z * x;
            z = x * v.y - v.x * y;
            return this;
        }
        
        public static Vector3D operator +(Vector3D v1, Vector3D v2)
        {
            return new Vector3D(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
        }

        public static Vector3D operator -(Vector3D v1, Vector3D v2)
        {
            return new Vector3D(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
        }

        public static Vector3D operator -(Vector3D v)
        {
            return new Vector3D(-v.x, -v.y, - v.z);
        }

        public static bool operator !=(Vector3D v1, Vector3D v2)
        {
            return !(v1 == v2);
        }

        public static bool operator ==(Vector3D v1, Vector3D v2)
        {
            if (Math.Abs(v1.x - v2.x) > MathHelper.EPS) return false;
            if (Math.Abs(v1.y - v2.y) > MathHelper.EPS) return false;
            if (Math.Abs(v1.z - v2.z) > MathHelper.EPS) return false;
            return true;
        }   
        
        public double Length()
        {
            return Math.Sqrt(x*x + y*y + z*z);
        }
        
        public Vector3D Normalize()
        {
            double len = Length();
            x /= len;
            y /= len;
            z /= len;
            return this;
        }

        public static Vector3D FromString(string point, char delimeter)
        {
            string[] s = point.Split(delimeter);
            return new Vector3D(Int32.Parse(s[0]), Int32.Parse(s[1]), Int32.Parse(s[2]));
        }

        public Color ToColor()
        {
            return Color.FromArgb((int)x, (int)y, (int)z);
        }
        
        public static Vector3D Zero
        {
            get 
            {
                return new Vector3D(0, 0, 0);
            }
        }     
        public override string ToString()
        {
            return x + " " + y + " " + z;
        }
    }
}
